package com.iotstudio.embeddedcloudplatform.util;

import com.iotstudio.embeddedcloudplatform.shiro.token.StatelessAuthenticationToken;

import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * token令牌的操作工具类
 * @author BeFondOfTaro
 * Created in 16:36 2018/1/18
 */
@Component
public class TokenUtil {
    /**
     * 验证成功后默认重置token保存时间
     */
    public static final long DEFAULT_EXPIRATION_TIME = 7;

    private static final Logger logger = LoggerFactory.getLogger(TokenUtil.class);

    /**
     * token缓存的key
     */
    private static final String TOKEN_KEY = "token";

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 创建消息摘要
     * 默认过期时间为7天
     *
     * @param token 用于生成digest的模型实体
     * @param password 用户密码
     * @return 生成的digest
     */
    public String createDigest(StatelessAuthenticationToken token, String password) {
        return createDigest(token,password,DEFAULT_EXPIRATION_TIME);
    }

    /**
     * 创建消息摘要
     *
     * @param token 用于生成digest的模型实体
     * @param password 用户密码
     * @param expirationTime 过期时间
     * @return 生成的digest
     */
    public String createDigest(StatelessAuthenticationToken token,String password, long expirationTime) {
        logger.info("--------创建digest消息摘要---------");
        String userId = token.getUserId();
        //进行消息摘要
        String digest = HmacSHA256Utils.digest(password, token.getParams());
        //将token存储到redis并设置过期时间
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        String userKey = getUserKey(userId);
        hashOperations.put(userKey,TOKEN_KEY,digest);
        System.out.println("token");
        redisTemplate.expire(userKey,expirationTime,TimeUnit.DAYS);
        logger.info("用户id:" + token.getUserId() + ",消息摘要已创建：" + digest);
        return digest;
    }

    public String getDigest(String userId){
        return (String) redisTemplate.opsForHash().get("user:"+userId,TOKEN_KEY);
    }

    /**
     * 验证token
     * 验证成功后默认重置token保存时间为7天
     *
     * @return
     */
    public boolean validToken(StatelessAuthenticationToken clientToken) {
        return validToken(clientToken, DEFAULT_EXPIRATION_TIME);
    }

    /**
     * 验证token
     *
     * @param expirationTime 重置token的保存时间(天)
     * @return
     */
    public boolean validToken(StatelessAuthenticationToken clientToken, long expirationTime) {
        boolean flag = false;
        String userIdInfo;
        if (clientToken != null) {
            String userId = clientToken.getUserId();
            userIdInfo = "用户id:" + userId;
            try {
                //判断token是否存在
                Object serverToken = redisTemplate.opsForHash().
                        get(
                                getUserKey(userId),
                                TOKEN_KEY
                        );
                if (serverToken == null || !serverToken.equals(clientToken.getClientDigest())) {
                    logger.info(userIdInfo + ",与服务端token匹配失败");
                } else {
                    flag = true;
                    redisTemplate.expire(getUserKey(userId),expirationTime,TimeUnit.DAYS);
                    logger.info(userIdInfo + ",token验证通过，重置保存时间为" + expirationTime + "天");
                }

            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        } else {
            logger.info("请求参数token为空，验证失败");
        }
        return flag;
    }

    public void deleteToken(String userId) {
        redisTemplate.delete(getUserKey(userId));
    }

    private String getUserKey(String userId){
        return "user:" + userId;
    }

    /**
     * 通过Shiro的SimpleAuthenticationInfo类来进行身份验证,
     * 验证成功后默认重置token保存时间为7天
     * @param userId
     * @param realmName
     * @param expirationTime
     * @return
     */
    public SimpleAuthenticationInfo validTokenBySimpleAuthenticationInfo(String userId, String realmName, long expirationTime) {
        String digest = (String) redisTemplate.opsForHash().get(getUserKey(userId),TOKEN_KEY);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userId, digest, realmName);
        redisTemplate.expire(getUserKey(userId),expirationTime,TimeUnit.DAYS);
        return authenticationInfo;
    }

    public SimpleAuthenticationInfo validTokenBySimpleAuthenticationInfo(String userId, String realmName) {
        return validTokenBySimpleAuthenticationInfo(userId, realmName, DEFAULT_EXPIRATION_TIME);
    }

}
